<template>
    <div class="basic-table-container" ref="wrapRef">
        <a-table 
            ref="tableRef"
            v-bind="getTableProps"
            @change="handleTableChange"
        >
            <template v-for="item in Object.keys($slots)" :key="item" #[item]="data">
                <slot :name="item" v-bind="data || {}"></slot>
            </template>
            <!-- 表头单元格 -->
            <template #headerCell="{ column }">
                <header-cell :column="column"/>
            </template>
            <template #bodyCell="data">
                <slot name="bodyCell" v-bind="data || {}"></slot>
            </template>
        </a-table>
    </div>
</template>

<script lang="ts">
import { basicProps } from './props';
import type { BasicTableProps, TableActionType, SizeType, BasicColumn } from './types/table';

import { usePagination } from './hooks/usePagination';
import { useColumns } from './hooks/useColumns';
import { useDataSource } from './hooks/useDataSource';
import { useLoading } from './hooks/useLoading';
import { useRowSelection } from './hooks/useRowSelection';
import { useCustomRow } from './hooks/useCustomRow';
import { useTableScroll } from './hooks/useTableScroll';
import { useTableScrollTo } from './hooks/useScrollTo';
import { useTableExpand } from './hooks/useTableExpand';
import { useTableFooter } from './hooks/useTableFooter';

import { isFunction, omit } from 'lodash-es';

import HeaderCell from './components/HeaderCell.vue';

export default defineComponent({
    name:'BasicTable',
    components: {
        HeaderCell,
    },
    props: basicProps,
    emits: [
        'register',
        'fetch-success',
        'fetch-error',
        'selection-change',
        'row-click',
        'row-dbClick',
        'row-contextmenu',
        'row-mouseenter',
        'row-mouseleave',
        'edit-end',
        'edit-cancel',
        'edit-row-end',
        'edit-change',
        'expanded-rows-change',
        'change',
        'columns-change',
    ],
    setup(props, { attrs, emit, slots, expose }) {
        
        const innerPropsRef = ref<Partial<BasicTableProps>>();
        const wrapRef = ref<Nullable<any>>();
        const tableRef = ref<Nullable<any>>();
        const tableData = ref<Recordable[]>([]);

        //在指定最小高度下,表格不出现滚动条,直接外层滚动
        const noScrollRt = reactive({
            enabled:true,//是否启用
            value:false,//当前状态
            minHeight: 120,//表格最小高度,如果低于该高度,将不出现滚动条
        });

        // 获取props传递数据
        const getProps = computed(() => {
            const options = { ...props, ...unref(innerPropsRef) } as BasicTableProps;
            return options;
        });

        // 加载方法
        const { getLoading, setLoading } = useLoading(getProps);

        // 处理分页方法
        const {
            getPaginationInfo,
            getPagination,
            setPagination,
            setShowPagination,
            getShowPagination,
        } = usePagination(getProps, tableData);

        // 处理表头栏方法
        const {
            getViewColumns,
            getColumns,
            setCacheColumnsByField,
            setColumns,
            getColumnsRef,
            getCacheColumns,
        } = useColumns(getProps, getPaginationInfo, tableData);

        // 处理行选择方法
        const {
            getRowSelection,
            getRowSelectionRef,
            getSelectRows,
            setSelectedRows,
            clearSelectedRowKeys,
            getSelectRowKeys,
            deleteSelectRowByKey,
            setSelectedRowKeys,
        } = useRowSelection(getProps, tableData, (emit as EmitType));

        // 处理表格数据方法
        const {
            handleTableChange: onTableChange,
            getDataSourceRef,
            getDataSource,
            getRawDataSource,
            setTableData,
            updateTableDataRecord,
            deleteTableDataRecord,
            insertTableDataRecord,
            findTableDataRecord,
            fetch,
            getRowKey,
            reload,
            getAutoCreateKey,
            updateTableData,
        } = useDataSource( getProps,{
            tableData,
            getPaginationInfo,
            setLoading,
            setPagination,
            clearSelectedRowKeys,
        }, (emit as EmitType));

        //计算滚动条后的回调
        const calcCallback = (height: number): boolean => {
            if (!noScrollRt.enabled) {
                return false;
            }

            const noScroll = height < noScrollRt.minHeight;
            noScrollRt.value = noScroll;

            return noScroll;
        };

        // 处理视图内容的滚动高度
        const { getScrollRef, redoHeight } = useTableScroll(
            getProps,
            tableRef,
            getColumnsRef,
            getRowSelectionRef,
            getDataSourceRef,
            wrapRef,
            calcCallback,
        );

        // 处理表格内容的滚动高度
        const { scrollTo } = useTableScrollTo(tableRef, getDataSourceRef);

        // 自定义行方法处理
        const { customRow } = useCustomRow(getProps, {
            setSelectedRowKeys,
            getSelectRowKeys,
            clearSelectedRowKeys,
            getAutoCreateKey,
            emit: (emit as EmitType),
        });

        // 处理表格展开方法
        const { getExpandOption, expandAll, expandRows, collapseAll } = useTableExpand(
            getProps,
            tableData,
            (emit as EmitType),
        );

        // 处理表格底部方法
        const { getFooterProps } = useTableFooter(
            getProps,
            getScrollRef,
            tableRef,
            getDataSourceRef,
        );


        // 获取表格传递的props数据
        const getTableProps = computed(() => {
            const dataSource = unref(getDataSourceRef);
            let propsData: Recordable = {
                ...attrs,
                customRow,
                ...unref(getProps),
                scroll: unref(getScrollRef),
                loading: unref(getLoading),
                tableLayout: 'fixed',
                rowSelection: unref(getRowSelectionRef),
                rowKey: unref(getRowKey),
                columns: toRaw(unref(getViewColumns)),
                pagination: toRaw(unref(getPaginationInfo)),
                dataSource,
                footer: unref(getFooterProps),
                ...unref(getExpandOption),
            };

            propsData = omit(propsData, ['class', 'onChange']);
            
            return propsData;
        });

        // 写入props传递的参数
        function setProps(props: Partial<BasicTableProps>) {
            innerPropsRef.value = { ...unref(innerPropsRef), ...props };
        }

        const tableAction: TableActionType = {
            reload,
            getSelectRows,
            clearSelectedRowKeys,
            getSelectRowKeys,
            setSelectedRows,
            deleteSelectRowByKey,
            setPagination,
            setTableData,
            updateTableDataRecord,
            deleteTableDataRecord,
            insertTableDataRecord,
            findTableDataRecord,
            redoHeight,
            setSelectedRowKeys,
            setColumns,
            setLoading,
            getDataSource,
            getRawDataSource,
            setProps,
            getRowSelection,
            getPaginationRef: getPagination,
            getColumns,
            getCacheColumns,
            emit: emit as EmitType,
            updateTableData,
            setShowPagination,
            getShowPagination,
            setCacheColumnsByField,
            expandAll,
            expandRows,
            collapseAll,
            scrollTo,
            getSize: () => {
                const getBindModel = unref(getTableProps) as any;
                return getBindModel?.size as SizeType;
            },
        };

        expose(tableAction);

        emit('register', tableAction);

        function handleTableChange(...args: any[]) {
            // @ts-ignoreno-ts
            onTableChange.call(undefined, ...args);
            emit('change', ...args);
            // 解决通过useTable注册onChange时不起作用的问题
            const { onChange } = unref(getProps);
            // @ts-ignoreno-ts
            onChange && isFunction(onChange) && onChange.call(undefined, ...args);
        }

        //从没滚动条到滚动条,需要重新计算下高度
        watch(() => noScrollRt, () => {
            if(noScrollRt.enabled && !noScrollRt.value){
                redoHeight();
            }
        },{ deep:true });

        return {
            wrapRef,
            tableRef,
            getTableProps,
            handleTableChange,
        };
    },
});
</script>

<style lang="less">
.basic-table-container {
    max-width: 100%;
    height: 100%;
    .ant-table {
        border-radius: 0px;
        background-color: rgba(193,231,255,.1);
        .ant-table-header {
            border-radius: 0px;
            border: 1px solid rgba(122,166,194,.14);
        }
    }
    .ant-table-thead >tr>th {
        background-color: rgba(2, 50, 80, 0.6);
        color: #c1e7ff;
        font-size: 14px;
        font-weight: 400;
    }
    .ant-table-container table>thead>tr:first-child >*:first-child{
        border-start-start-radius: 0px;
    }
    .ant-table-container table>thead>tr:first-child >*:last-child {
        border-start-end-radius: 0px;
    }
    .ant-table-thead >tr>th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan])::before{
        width: 0px;
    }
    .ant-table-wrapper .ant-table-cell-scrollbar:not([rowspan]){
        box-shadow: none;
    }

    .ant-table.ant-table-middle .ant-table-title,
    .ant-table.ant-table-middle .ant-table-footer,
    .ant-table.ant-table-middle .ant-table-thead>tr>th,
    .ant-table.ant-table-middle tfoot>tr>th{
        padding: 4px 2px;
        border-bottom: 1px solid rgba(193,231,255,.3);
    }
    .ant-table.ant-table-middle .ant-table-tbody>tr>td,
    .ant-table.ant-table-middle tfoot>tr>td {
        padding: 10px 8px;
        font-size: 12px;
        color: #fff;
        border-top: 1px solid rgba(193,231,255,.3);
    }

    .ant-table:not(.ant-table-bordered) .ant-table-tbody >tr:last-child>td{
        border-bottom: 1px solid rgba(193,231,255,.3);
    }

    .ant-table-tbody >tr.ant-table-row:hover>td, 
    .ant-table-tbody >tr >td.ant-table-cell-row-hover {
        background: rgba(193,231,255,.4);
    }

    .ant-table-tbody>tr.ant-table-placeholder:hover>td {
        background-color: rgba(193,231,255,.1);
    }
    .ant-empty-description { color: #fff; }

    //分页样式
    .ant-table-pagination.ant-pagination {
        margin: 12px 0;
    }

    .ant-pagination .ant-pagination-prev,
    .ant-pagination .ant-pagination-next {
        color: #c1e7ff;
    }
    .ant-pagination .ant-pagination-prev button,
    .ant-pagination .ant-pagination-next button{
        color: #a9b8c1;
    }
    .ant-pagination .ant-pagination-disabled .ant-pagination-item-link,
    .ant-pagination .ant-pagination-disabled:hover .ant-pagination-item-link {
        color: #57666f;
    }
    
    .ant-pagination .ant-pagination-item a {
        color: #fff;
    }
    .ant-pagination .ant-pagination-item-active a {
        color: @primary-color;
    }
    .ant-pagination .ant-pagination-item-active{
        background-color: rgba(255, 255, 255, 0);
        border-color: rgba(255, 255, 255, 0);
    }
}
</style>